/*
Copyright (c) 2012, 2013 Regents of the University of California
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions 
are met:

 - Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
 - Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the
   distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
OF THE POSSIBILITY OF SUCH DAMAGE.
*/

function updateTree(projectName) {
  	if (projectName == 'sdh'){
		var trees = [
        [{tag: "Metadata/SourceName",
        restrict: "Metadata/SourceName = 'Sutardja Dai Hall BACnet'"},
        {"prefixTag": "Path"}],
		];
	}
	else if (projectName == 'bancroft'){
		var trees = [
        [{tag: "Metadata/SourceName",
        restrict: "Metadata/SourceName = 'Bancroft Library' or Metadata/Extra/Project = 'bancroft'"},
        {"prefixTag": "Path"}],
		];
	} 
	else{
    	var trees = [
        [{tag: "Metadata/SourceName",
        restrict: "Metadata/SourceName like '% BMS' or Metadata/SourceName like '% BACnet' and Metadata/Extra/Project = '" + projectName + "'"},
        {"prefixTag": "Path"}],
		];
	}
  var treeidx = 0;
  $("#treeParent").html('<div id=tree></div>');
  makeTagTree("#tree", trees[treeidx], page_args.path ? page_args.path.split(",") : []);
}

// escape tag names and values for inclusion in a query
function tag_escape(x){
  return x.replace('"', '\\\"');
}

// open a path in the tree
// path: an array of strings, one per level of the tree to open.
// nodes will be loaded if not already there
function treeOpenPath(path) {
  if (path.length) {
    var thisseg = unescape(path.shift());
    $("#__tree").jstree("open_node", $("#__tree a:containsexactly('\xA0" + thisseg + "') :parent"), 
                          function () { treeOpenPath(path); });
  }
}

// Build a tag tree
// div: jquery div selected, place to build tree
// tree_order: an array representing the tree configuration; a list of
//   level configurations
function makeTagTree(div, tree_order, openpath) {
 $(function() {
     // var last_selected = [];
     console.log(div)
     var separator = '/';

     // get the tag name a particular tree level uses
     function getTag(ob) {
       if ($.type(ob) == 'string') {
         return ob;
       } else if ("tag" in ob) {
         return ob.tag;
       } else if ("prefixTag" in ob) {
         return ob.prefixTag;
       }
       return "";
     }

     function isPrefixTree() {
       return $.type(tree_order[tree_order.length-1]) == 'object' &&
         "prefixTag" in tree_order[tree_order.length-1];
     }

     // build the "where" part of a query based on a path and a
     // particular node.
     function buildClauses(p, node) {
        var clauses = [];
        for (var i = 0; i < Math.min(p.length, tree_order.length); i++) {
          if ($.type(tree_order[i]) == "string") {
            clauses.push(tree_order[i] + " = \"" + tag_escape(p[i]) + '"');
          } else if ("tag" in tree_order[i]) {
            clauses.push(tree_order[i].tag + " = \"" + tag_escape(p[i]) + '"');

            // add any restrict clauses
            if ("restrict" in tree_order[i]) {
              clauses.push('(' + tree_order[i].restrict + ')');
            }
          }
        }
        if (p.length >= tree_order.length && isPrefixTree()) {
          // if we're off the end of a prefix tree, condition on the
          // part of the prefix we've at now.
          var finalsep = $(node).hasClass("jstree-leaf") ? '' : separator + "%";
          clauses.push('(' + tree_order[tree_order.length - 1].prefixTag + " like \"" + 
                       tag_escape(separator + p.slice(tree_order.length-1).join(separator)) + 
                       finalsep + "\")");
        }
        if (p.length == 0 && $.type(tree_order[0]) == "object" && 
            "restrict" in tree_order[0]) {
          clauses.push('(' + tree_order[0].restrict + ')');          
        }
       // make sure the results have the tag for the tree level we're
       // interested in.
       if (p.length + 1 < tree_order.length) {
          clauses.push('(has ' + getTag(tree_order[p.length + 1]) + ')');
       }
       return clauses.join(" and ");
     }

     $(div).append($("<div/>", {
         id: "__tree" }));

     $("#__tree")
       .jstree(
         {
           "plugins" : [ "themes", "json_data", "ui", "ajax", "dnd", "crrm", "types"], 
           //not sure why the always_copy doesn't work--but I guess it is actually ok to move so you know which ones you have
           //"crrm": { "move": { "always_copy": "true" } },
           "json_data" : {
             // dynamically open nodes by querying when they're opened and adding the
             // appropriate children
             "ajax" : {
               "type" : "POST",
               "url" : backend + "/api/query?" + private_flags,
               "data" : function (n) {
                 // load data for a tree level
                 // generate the query which is send as the POST payload
                 var p = $("#__tree").jstree("get_path", n);
                 var query = "select distinct ";
                 if (n == -1) {
                   p = [];
                 }
                 // find the tag name we want to select at this level
                 if (p.length < tree_order.length ||
                     (p.length >= tree_order.length && isPrefixTree(tree_order))) {
                   if ($.type(tree_order[p.length]) == "string") {
                     // if it's a normal tree, this means the tag at this level
                     query += tree_order[p.length];
                   } else if (p.length >= tree_order.length - 1 &&
                             "prefixTag" in tree_order[tree_order.length-1]) {
                     // if it's a prefixTree and we're generating
                     // that, we always use the prefixTag
                     query += tree_order[tree_order.length-1].prefixTag;
                   } else if ("tag" in tree_order[p.length]) {
                     // it might be a config dict at this level rather
                     // than a string.
                     query += tree_order[p.length].tag;
                   }
                   // build the where clauses which enforce our
                   // selections for the levels above us.
                   var clauses = buildClauses(p, n);
                   if (clauses.length)
                     query += " where " + clauses;
                   console.log(query);
                   return query;
                 } 
                 return undefined;
               },
               "success" : function (resp, status, req, node) {
                 // process the returned query data into a jstree struct
                 var obj = eval(resp);
                 var rv = [];
                 var p = $("#__tree").jstree("get_path", node);
                 p = (p == false) ? 0 : p.length;
                 if (p < tree_order.length - 1 || !isPrefixTree()) {
                   // write tree nodes for the non-prefix-tree portion of the tree
                   var sortfn = ($.type(tree_order[p]) == "object" &&
                                 "sortfn" in tree_order[p]) ? tree_order[p].sortfn : undefined;
                   obj.sort(sortfn);
                   var state = p == tree_order.length - 1 ? false : "closed";
                   var icon = (!state || ($.type(tree_order[p]) == "object" &&
                                          "defaultSubStream" in tree_order[p])) ? 
                     "/static/smap/img/file.png" :
                     "/static/smap/img/folder.png";
                   for (i = 0; i < obj.length; i++) {
                     rv[i] = {"data" : {
                                "title": obj[i],
                                "attr": {class:"jstree-draggable"},
                               // "icon": icon,
                              },
                              
                              "state": state,
                             }
                   }
                 } else if (isPrefixTree()) {
                   // build a prefix tree 
                   var level = p - tree_order.length + 1 + 1;
                   var tags = {};
                   var sortfn = ($.type(tree_order[tree_order.length - 1]) == "object" &&
                                 "sortfn" in tree_order[tree_order.length - 1]) ? 
                     tree_order[tree_order.length - 1].sortfn : undefined;

                   // we're in a prefix tree... 
                   // find the distinct tags, and decide if they are open or closed
                   for (i = 0; i < obj.length; i++) {
                     var cmps = obj[i].split(separator);
                     if (cmps.length >= level) {
                       var thisstate = cmps.length > level + 1 ? "closed" : false;
                       // console.log("checking " + cmps[level] + " " + tags[cmps[level]]);
                       if (tags[cmps[level]] == undefined ||
                           tags[cmps[level]] == false) {
                         tags[cmps[level]] = thisstate;
                       }
                     }
                   }

                   // write back the consolidated tag values
                   for (var tv in tags) {
                     rv[rv.length] = {"data" : {
                                        "title" : tv,
                                        //"icon" : "/static/smap/img/file.png",
                                      },
                                      "attr": {class:"jstree-draggable"},
                                      "state": tags[tv]
                                      };
                   }
                   // we have to sort after splitting up the prefix
                   // tag value since we only want to sort based on
                   // this one particular level.
                   rv.sort(function (x, y) {
                             if (sortfn) return sortfn(x.data.title, y.data.title);
                             else return (x.data.title < y.data.title ? -1 : 
                                          (x.data.title > y.data.title ? 1 : 0));
                           });
                 }
                  if (node == -1){
                  	var time_range = getTimeRange();
					var start = time_range[0];
					var end = time_range[1];
                 	$.ajax({
						type: "GET",
						url: "/pmp/tree/",
						data: {'projectId': sessvars.sessionObj['projectId'], 'analysisType': 'setpoint', 'stratDevice': 'none', 'start_time': start, 'end_time': end},
						success: function(data){
							rv.push.apply(rv, data)        
						},
						async: false
					});	
                 }
                 return rv;
               }
             }
           },
            "types" : {
			// I want only `drive` nodes to be root nodes 
			// This will prevent moving or creating any other type as a root node
			"valid_children" : [ "root" ],
			"types" : {
				// The default type
				"root" : {"valid children" : "folder"},
				"default" : {"icon" : {
						"image" : "/static/smap/img/folder.png",
					},},
				"file" : {
					// I want this type to have no children (so only leaf nodes)
					// In my case - those are files
					"valid_children" : "none",
					// If we specify an icon for the default type it WILL OVERRIDE the theme icons
					"icon" : {
						"image" : "/static/smap/img/file.png",
					}
				},
				// The `folder` type
				"folder" : {
					// can have files and other folders inside of it, but NOT `drive` nodes
					"valid_children" : [ "default", "folder", "file" ],
					"icon" : {
						"image" : "/static/smap/img/folder.png",
					},
				},
			}
		},
           "ui": {
             "select_multiple_modifier" : "alt",
           },
         })
       .bind("dblclick.jstree", function(event) {
               var node = $(event.target).closest("li");
               if ($(node).hasClass("jstree-leaf")) {
                 $("#__tree").jstree("select_node", node);
               } else {
                 $("#__tree").jstree("toggle_node", node);
               }
             })
       .bind("select_node.jstree", function(event, data) {
               // updateSelection();
             })
       .bind("deselect_node.jstree", function(event, data) {
               // updateSelection();
             })
       .bind("loaded.jstree", function() {
               treeOpenPath(openpath);
             });
   });
}

